package timing.ukulele.portal.service;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson2.JSON;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import timing.ukulele.common.data.ResponseCode;
import timing.ukulele.common.util.TreeUtil;
import timing.ukulele.data.portal.data.AntMenuConfigAccessTree;
import timing.ukulele.data.portal.data.AntMenuTree;
import timing.ukulele.data.portal.view.SysMenuPermissionVO;
//import timing.ukulele.portal.dictionary.RoleTypeEnum;
import timing.ukulele.portal.mapper.AntMenuMapper;
import timing.ukulele.portal.mapper.AntRoleMenuMapper;
import timing.ukulele.portal.persistent.*;
import timing.ukulele.portal.util.UkuleleRbacUtil;
import timing.ukulele.share.Constant;
import timing.ukulele.share.RoleTypeEnum;
import timing.ukulele.share.UserLabelEnum;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class AntMenuService extends BaseOperatorService<AntMenuMapper, AntMenu> {
    private final AntRoleMenuMapper roleMenuMapper;
    private final SysMenuPermissionService menuPermissionService;
    private final SysResourceService menuResourceService;

    @Autowired
    public AntMenuService(AntRoleMenuMapper roleMenuMapper, SysMenuPermissionService menuPermissionService,
                          SysResourceService menuResourceService) {
        this.roleMenuMapper = roleMenuMapper;
        this.menuPermissionService = menuPermissionService;
        this.menuResourceService = menuResourceService;
    }

    /**
     * 获取角色的菜单及其资源与权限，包含待选的和已选的
     *
     * @param roleId  角色id
     * @param type    角色类型
     * @param isSuper 是否为超管
     * @return 配置信息
     */
    public List<AntMenuConfigAccessTree> getRoleMenuConfig(Long roleId, Integer type, Boolean isSuper) {
//        // 1.所有的菜单
//        List<AntMenu> menus = this.list();
//        if (CollectionUtils.isEmpty(menus))
//            return null;
//        List<AntMenu> allMenu = menus;
//        // 非super
//        if (isSuper == null || !isSuper) {
//            allMenu = menus.stream().filter(item -> {
//                String aclString = item.getAcl();
//                if (StringUtils.hasText(aclString)) {
//                    List<String> aclList = JSON.parseArray(aclString, String.class);
//                    if (type.equals(RoleTypeEnum.SYSTEM.getCode())) { // 系统角色
//                        // 只有一个权限，并且是supper
//                        if (aclList.size() == 1 && aclList.contains(UserLabelEnum.SUPER.getLabel())) {
//                            return false;
//                        }
//                    } else { //业务角色
//                        if (aclList.contains(UserLabelEnum.SUPER.getLabel())
//                                || aclList.contains(UserLabelEnum.ADMIN.getLabel())) {
//                            return false;
//                        }
//                    }
//                }
//                return true;
//            }).collect(Collectors.toList());
//        }
//        if (CollectionUtils.isEmpty(allMenu))
//            return null;
        // 1.查询所有菜单
        List<AntMenu> allMenusList = this.list();
        List<AntMenu> antMenuList = new ArrayList<>(0);
        // 如果是运维的话，默认所有菜单
        if(RoleTypeEnum.OPERATOR.getValue().equals(type)) {
            antMenuList = allMenusList;
        }else{
            // 将全部菜单数据按照ID转为map
            Map<Long, AntMenu> allAntMenuMap = allMenusList.stream().collect(Collectors.toMap(AntMenu::getId, account -> account));
            // 获取角色和菜单级别对应关系
            List<Integer> menuGradeList = UkuleleRbacUtil.getMenuGradeByRoleType(type);
            // 按照角色级别查询菜单数据
            List<AntMenu> dbMenulist = this.lambdaQuery().in(AntMenu::getGrade, menuGradeList).list();
            Map<Long, AntMenu> dbMenuMap = dbMenulist.stream().collect(Collectors.toMap(AntMenu::getId, account -> account));
            antMenuList.addAll(dbMenulist);
            // 根据按照条件查询出来的菜单数据，和查询出来全部的菜单数据进行比对，依次循环找出子节点的父节点不存在的数据并放到一个新的list里面，父节点可能也可以作为子节点，所以需要循环判断
            for (AntMenu menu : dbMenulist) {
                if(menu.getParentId() < 1) {
                    continue;
                }
                if (dbMenuMap.get(menu.getParentId()) == null) {
                    AntMenu parentMenu = allAntMenuMap.get(menu.getParentId());
                    antMenuList.add(parentMenu);
                    dbMenuMap.put(parentMenu.getId(), parentMenu);
                    while (parentMenu.getParentId() != null && parentMenu.getParentId() > 0) {
                        AntMenu parent = allAntMenuMap.get(parentMenu.getParentId());
                        if (parent != null && dbMenuMap.get(parentMenu.getParentId()) == null) {
                            antMenuList.add(parent);
                            dbMenuMap.put(parent.getId(), parent);
                            parentMenu = parent;
                        } else {
                            break;
                        }
                    }
                }
            }
        }
        if(CollectionUtil.isEmpty(antMenuList)) {
            return null;
        }
        // 2.所有的菜单权限
        List<SysMenuPermission> permissionList = menuPermissionService.list();
        // 3.所有的菜单资源
        List<SysResource> resourceList = menuResourceService.list();
        // 4.当前角色已配置的菜单
        List<AntRoleMenu> roleMenuList = this.roleMenuMapper.selectRoleMenu(roleId);
        // 5.当前角色已经配置的权限
        List<SysRoleMenuPermission> rolePermissionList = this.roleMenuMapper.getRolePermission(roleId);
        // 6.所有的菜单权限map
        Map<Long, List<SysMenuPermission>> permissionMap = null;
        if (!CollectionUtils.isEmpty(permissionList)) {
            permissionMap = new HashMap<>();
            for (SysMenuPermission menuPermission : permissionList) {
                List<SysMenuPermission> menuPermissions = permissionMap.computeIfAbsent(menuPermission.getMenuId(), k -> new ArrayList<>());
                menuPermissions.add(menuPermission);
            }
        }
        // 7.所有的菜单的资源的map
        Map<Long, List<SysResource>> resourceMap = null;
        if (!CollectionUtils.isEmpty(resourceList)) {
            resourceMap = new HashMap<>();
            for (SysResource menuResource : resourceList) {
                List<SysResource> menuResources = resourceMap.computeIfAbsent(menuResource.getGroupId(), k -> new ArrayList<>());
                menuResources.add(menuResource);
            }
        }
        // 8.当前角色已经配置的菜单map
        Map<Long, List<AntRoleMenu>> roleMenuMap = null;
        if (!CollectionUtils.isEmpty(roleMenuList)) {
            roleMenuMap = new HashMap<>();
            for (AntRoleMenu roleMenu : roleMenuList) {
                List<AntRoleMenu> roleMenus = roleMenuMap.computeIfAbsent(roleMenu.getMenuId(), k -> new ArrayList<>());
                roleMenus.add(roleMenu);
            }
        }
        // 9.当前角色已经配置的权限的map
        Map<Long, List<SysRoleMenuPermission>> rolePermissionMap = null;
        if (!CollectionUtils.isEmpty(rolePermissionList)) {
            rolePermissionMap = new HashMap<>();
            for (SysRoleMenuPermission menuPermission : rolePermissionList) {
                List<SysRoleMenuPermission> permissions = rolePermissionMap.computeIfAbsent(menuPermission.getMenuId(), k -> new ArrayList<>());
                permissions.add(menuPermission);
            }
        }
        // 组装数据
        List<AntMenuConfigAccessTree> menuList = new ArrayList<>(antMenuList.size());
        Long minParentId = null;
        for (AntMenu menu : antMenuList) {
            if (minParentId == null) {
                minParentId = menu.getParentId();
            } else if (minParentId > menu.getParentId()) {
                minParentId = menu.getParentId();
            }
            AntMenuConfigAccessTree node = new AntMenuConfigAccessTree();
            node.setId(menu.getId());
            node.setParentId(menu.getParentId());
            node.setDisabled(menu.getDisabled());
            node.setKey(menu.getKey());
            node.setTitle(menu.getText());
            node.setDisabled(menu.getDeleted());
            node.setType(menu.getType());
            node.setGrade(menu.getGrade());
            node.setModule(menu.getModule());

            // 设置是否配置了该菜单
            boolean contained = !CollectionUtils.isEmpty(roleMenuMap) && roleMenuMap.containsKey(menu.getId());
//            node.setSelected(contained);
            node.setChecked(contained);
            //设置权限
            if (!CollectionUtils.isEmpty(permissionMap) && permissionMap.containsKey(menu.getId())) {
                List<SysMenuPermissionVO> permissionVoList = new ArrayList<>();
                List<SysRoleMenuPermission> roleMenuPermissions = null;
                if (!CollectionUtils.isEmpty(rolePermissionMap)) {
                    roleMenuPermissions = rolePermissionMap.get(menu.getId());
                }
                List<SysMenuPermission> menuPermissions = permissionMap.get(menu.getId());
                if (!CollectionUtils.isEmpty(menuPermissions)) {
                    for (SysMenuPermission permission : menuPermissions) {
                        SysMenuPermissionVO vo = new SysMenuPermissionVO();
                        BeanUtils.copyProperties(permission, vo);
                        vo.setChecked(!CollectionUtils.isEmpty(roleMenuPermissions)
                                && roleMenuPermissions.stream().anyMatch(item ->
                                item.getPermissionId().equals(permission.getId())));
                        permissionVoList.add(vo);
                    }
                    node.setPermissionList(permissionVoList);
                }
            }
            menuList.add(node);
        }
        return TreeUtil.buildByRecursive(menuList, minParentId == null ? 0L : minParentId);
    }

    /**
     * 配置角色的菜单及其资源与权限
     *
     * @param role   角色
     * @param config 配置信息
     * @return 成功与否
     */
    @Transactional(rollbackFor = Exception.class)
    public ResponseCode setRoleMenuConfig(SysRole role, List<AntMenuConfigAccessTree> config) {
        if (CollectionUtils.isEmpty(config) || role == null)
            return ResponseCode.PARA_ERROR;

        //找出所有节点
        List<AntMenuConfigAccessTree> nodeList = new ArrayList<>();
        for (AntMenuConfigAccessTree menu : config) {
            nodeList.add(menu);
            this.findChildren(menu, nodeList);
        }
        List<SysMenuPermissionVO> checkedPermissionList = new ArrayList<>();
        for (AntMenuConfigAccessTree child : nodeList) {
            List<SysMenuPermissionVO> permissionList = child.getPermissionList();
            if (!CollectionUtils.isEmpty(permissionList)) {
                checkedPermissionList.addAll(permissionList.stream().filter(vo -> vo.getChecked() != null && vo.getChecked()).toList());
            }
        }
        Set<Long> checkedMenuSet = new HashSet<>();
        List<SysRoleMenuPermission> permissionList = new ArrayList<>(checkedPermissionList.size());
        for (SysMenuPermissionVO vo : checkedPermissionList) {
            SysRoleMenuPermission po = new SysRoleMenuPermission();
            po.setRoleId(role.getId());
            po.setMenuId(vo.getMenuId());
            po.setPermissionId(vo.getId());
            po.setTenantId(role.getTenantId());
            permissionList.add(po);
            checkedMenuSet.add(vo.getMenuId());
        }
        Set<Long> parents = new HashSet<>();
        for (Long menu : checkedMenuSet) {
            findParent(nodeList, menu, parents);
        }
        checkedMenuSet.addAll(parents);
        List<AntRoleMenu> roleMenuList = new ArrayList<>(checkedMenuSet.size());
        for (Long menu : checkedMenuSet) {
            AntRoleMenu po = new AntRoleMenu();
            po.setMenuId(menu);
            po.setRoleId(role.getId());
            po.setTenantId(role.getTenantId());
            roleMenuList.add(po);
        }
        // 先删除
        this.roleMenuMapper.deleteRolePermission(role.getId());
        this.roleMenuMapper.deleteRoleMenu(role.getId());
        // 插入
        if (!CollectionUtils.isEmpty(permissionList))
            this.roleMenuMapper.batchAddRolePermission(permissionList);
        if (!CollectionUtils.isEmpty(roleMenuList))
            this.roleMenuMapper.batchAddRoleMenu(roleMenuList);
        return ResponseCode.SUCCESS;
    }


    public List<AntMenuTree> getMenuTreeByRole(String userLabel, List<Long> roleIds, Integer type, boolean resource, String module) {
        // 1.角色已配置的菜单
        Set<Long> roleMenuIds = this.roleMenuMapper.selectRoleMenuByIds(roleIds,
                Optional.ofNullable(module).orElse(Constant.PLATFORM_APPLICATION_DEFAULT));
        if (CollectionUtils.isEmpty(roleMenuIds))
            return null;
        // 2.所有启用的菜单
        List<AntMenu> allActiveMenus = this.lambdaQuery().eq(AntMenu::getDeleted, false).eq(AntMenu::getType, type == null ? 0L : type).list();
        if (CollectionUtils.isEmpty(allActiveMenus))
            return null;
        Map<Long, AntMenu> menuMap = allActiveMenus.stream().collect(Collectors.toMap(AntMenu::getId, Function.identity(), (key1, key2) -> key2));

        List<AntMenuTree> list = new ArrayList<>(roleMenuIds.size());

        // 3.角色已配置的权限
        List<SysRoleMenuPermission> rolePermissions = this.roleMenuMapper.getRolePermissionByIds(roleIds);
        Map<Long, Set<Long>> roleMenuPermissionMap = null;
        if (!CollectionUtils.isEmpty(rolePermissions)) {
            roleMenuPermissionMap = new HashMap<>();
            for (SysRoleMenuPermission rolePermission : rolePermissions) {
                Set<Long> permissions = roleMenuPermissionMap.computeIfAbsent(rolePermission.getMenuId(), k -> new HashSet<>());
                permissions.add(rolePermission.getPermissionId());
            }
        }
        // 4.菜单的权限
        List<SysMenuPermission> menuPermissions = menuPermissionService.lambdaQuery().eq(SysMenuPermission::getDeleted, false)
                .in(SysMenuPermission::getMenuId, roleMenuIds).select(SysMenuPermission::getId, SysMenuPermission::getMenuId, SysMenuPermission::getPermission).list();
        Map<Long, Map<Long, String>> menuPermissionMap = null;
        if (!CollectionUtils.isEmpty(menuPermissions)) {
            menuPermissionMap = new HashMap<>();
            for (SysMenuPermission menuPermission : menuPermissions) {
                Map<Long, String> permissionSet = menuPermissionMap.computeIfAbsent(menuPermission.getMenuId(), k -> new HashMap<>());
                permissionSet.put(menuPermission.getId(), menuPermission.getPermission());
            }
        }
        // 7.组装数据
        for (Long roleMenuId : roleMenuIds) {
            AntMenu menu = menuMap.get(roleMenuId);
            if (menu == null)
                continue;
            AntMenuTree node = new AntMenuTree();
            BeanUtils.copyProperties(menu, node);
            if (StringUtils.hasText(menu.getAcl())) {
                node.setAcl(JSON.parseArray(menu.getAcl(), String.class));
            }
            // 设置权限
            if (!CollectionUtils.isEmpty(roleMenuPermissionMap) && !CollectionUtils.isEmpty(menuPermissionMap)) {
                Set<Long> permissionIds = roleMenuPermissionMap.get(menu.getId());
                if (!CollectionUtils.isEmpty(permissionIds)) {
                    List<String> permissionList = new ArrayList<>();
                    for (Long permissionId : permissionIds) {
                        Map<Long, String> permissionMap = menuPermissionMap.get(menu.getId());
                        if (!CollectionUtils.isEmpty(permissionMap)) {
                            if (permissionMap.containsKey(permissionId)) {
                                permissionList.add(permissionMap.get(permissionId));
                            }
                        }
                    }
                    node.setPermissionList(permissionList);
                }
            }
            list.add(node);
        }
        list = list.stream().sorted(Comparator.comparing(AntMenuTree::getRank)).collect(Collectors.toList());
        return TreeUtil.buildByRecursive(list, 0L);
    }

    private void findChildren(AntMenuConfigAccessTree node, List<AntMenuConfigAccessTree> children) {
        if (node == null || children == null) {
            return;
        }
        if (!CollectionUtils.isEmpty(node.getChildren())) {
            for (AntMenuConfigAccessTree child : node.getChildren()) {
                children.add(child);
                this.findChildren(child, children);
            }
        }
    }

    private void findParent(List<AntMenuConfigAccessTree> nodeList, Long nodeId, Set<Long> parents) {
        for (AntMenuConfigAccessTree node : nodeList) {
            if (node.getId() == nodeId) {
                if (node.getParentId() != 0) {
                    parents.add(node.getParentId());
                    this.findParent(nodeList, node.getParentId(), parents);
                }
            }
        }
    }

}
